package quotation.utils;

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class CommonFieldUtil {

    public static class CommonField {
        public final static String PH_CREATOR = "phCreator";
        public final static String PH_USER_ID = "phUserId";
        public final static String PH_INSERT_DT = "phInsertDt";
        public final static String PH_UPDATE_DT = "phUpdateDt";
        public final static String PH_EDITOR_ID = "phEditorId";
        public final static String PH_EDITOR_NAME = "phEditorName";
    }

    public static class CommonCol {
        public final static String PH_CREATOR = "ph_creator";
        public final static String PH_USER_ID = "ph_user_id";
        public final static String PH_INSERT_DT = "ph_insert_dt";
        public final static String PH_UPDATE_DT = "ph_update_dt";
        public final static String PH_EDITOR_ID = "ph_editor_id";
        public final static String PH_EDITOR_NAME = "ph_editor_name";
    }

    public static <T> T commonSaveFieldValue(T entity) {
        LoginInfoUtil loginInfo = LoginInfoUtil.getInstance();

        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            //将私有属性改为可访问
            if (!Modifier.isPublic(field.getModifiers())) {
                field.setAccessible(true);
            }
            if (CommonField.PH_INSERT_DT.equals(name)) {
                ReflectionUtils.setField(field, entity, LocalDateTime.now());
            } else if (CommonField.PH_UPDATE_DT.equals(name)) {
                ReflectionUtils.setField(field, entity, LocalDateTime.now());
            } else if (CommonField.PH_EDITOR_ID.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo != null ? loginInfo.getUserId() : 0L);
            } else if (CommonField.PH_EDITOR_NAME.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo != null ? loginInfo.getName() : "system");
            }
        }
        return entity;
    }

    public static <T> T commonUpdateFieldValue(T entity) {
        LoginInfoUtil loginInfo = LoginInfoUtil.getInstance();
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            //将私有属性改为可访问
            if (!Modifier.isPublic(field.getModifiers())) {
                field.setAccessible(true);
            }
            if (CommonField.PH_UPDATE_DT.equals(name)) {
                ReflectionUtils.setField(field, entity, LocalDateTime.now());
            } else if (CommonField.PH_EDITOR_ID.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo != null ? loginInfo.getUserId() : 0L);
            } else if (CommonField.PH_EDITOR_NAME.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo != null ? loginInfo.getName() : "system");
            }
        }
        return entity;
    }

    public static <T> T setCommonFieldValue(T entity, LoginInfoUtil loginInfo) {
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            //将私有属性改为可访问
            if (!Modifier.isPublic(field.getModifiers())) {
                field.setAccessible(true);
            }
            if (CommonField.PH_CREATOR.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo.getName());
            } else if (CommonField.PH_USER_ID.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo.getUserId());
            } else if (CommonField.PH_INSERT_DT.equals(name)) {
                ReflectionUtils.setField(field, entity, LocalDateTime.now());
            } else if (CommonField.PH_UPDATE_DT.equals(name)) {
                ReflectionUtils.setField(field, entity, LocalDateTime.now());
            } else if (CommonField.PH_EDITOR_ID.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo.getUserId());
            } else if (CommonField.PH_EDITOR_NAME.equals(name)) {
                ReflectionUtils.setField(field, entity, loginInfo.getName());
            }
        }
        return entity;
    }

    /**
     * add by wangzefeng 2022年8月2日
     * 两个bean所有 Integer、Long、BigDecimal类型的字段数据汇总
     */
    public static <T> void addNumber(T total, T child, List<String> ignoreFields) {
        Field[] fields = total.getClass().getDeclaredFields();
        Field[] childFields = child.getClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                String name = field.getName();
                Class<?> type = field.getType();
                //将私有属性改为可访问
                if (!Modifier.isPublic(field.getModifiers())) {
                    field.setAccessible(true);
                }
                boolean b = Integer.class.equals(type) || Long.class.equals(type) || BigDecimal.class.equals(type);
                if (b && !ignoreFields.contains(name)) {
                    for (Field field1 : childFields) {
                        if (field1.getName().equals(name)) {
                            field1.setAccessible(true);
                            if (Integer.class.equals(type)) {
                                int i = (Integer) field1.get(child) + (Integer) field.get(total);
                                field.set(total, i);
                            }
                            if (Long.class.equals(type)) {
                                long i = (Long) field1.get(child) + (Long) field.get(total);
                                field.set(total, i);
                            }
                            if (BigDecimal.class.equals(type)) {
                                BigDecimal i = ((BigDecimal) field1.get(child)).add((BigDecimal) field.get(total));
                                field.set(total, i);
                            }
                        }
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 只有在数据量少的情况下使用，数据量多了用反射反倒会影响性能
     */
    public static <T> void treeToList(List<T> result, List<Long> levels, T obj, String fieldName) {
        try {
            Object o = obj.getClass().newInstance();
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            Map<String, Field> fieldMap = new HashMap<>();
            for (Field declaredField : declaredFields) {
                String name = declaredField.getName();
                fieldMap.put(name, declaredField);
            }
            Field field = fieldMap.get(fieldName);
            //将私有属性改为可访问
            if (!Modifier.isPublic(field.getModifiers())) {
                field.setAccessible(true);
            }
            Long aLong = (Long) field.get(obj);
            //有可能存在跳级导出，所以只能在这里判断
            if (levels.contains(aLong)) {
                BeanUtils.copyProperties(obj, o, "children");
                result.add((T) o);
            }
            Field childrenField = fieldMap.get("children");
            //将私有属性改为可访问
            if (!Modifier.isPublic(childrenField.getModifiers())) {
                childrenField.setAccessible(true);
            }
            List<T> children = (List<T>) childrenField.get(obj);
            if (!CollectionUtils.isEmpty(children)) {
                for (T child : children) {
                    treeToList(result, levels, child, fieldName);
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}
